package com.say.config;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Aspect
@Configuration
public class TransactionConfiguration {

  /**
   * 切面 Service
   */
  private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.say.*.service.impl.*.*(..))";

  @Autowired
  private PlatformTransactionManager transactionManager;

  /**
   */
  private static final String[] DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES = {
          "add*",
          "save*",
          "insert*",
          "delete*",
          "update*",
          "edit*",
          "batch*",
          "create*",
          "remove*",
  };

  /**
   * 默认的只读事务
   */
  private static final String[] DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES = {
          "get*",
          "count*",
          "find*",
          "query*",
          "select*",
          "list*",
          "*",
  };


  /**
   * 事务拦截器
   *
   * @return
   */
  @Bean
  public TransactionInterceptor txAdvice() {
    NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

    /*只读事务，不做更新操作*/
    RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
    readOnlyTx.setReadOnly(true);
    readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);

    /*当前存在事务就使用当前事务，当前不存在事务就创建一个新的事务*/
    RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
    requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
    requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

    Map<String, TransactionAttribute> txMap = new HashMap<>(16);
    /*配置事务方法的前缀*/
    for (String key : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
      txMap.put(key, requiredTx);
    }
    /*配置只读事务方法的前缀*/
    for (String key : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
      txMap.put(key, readOnlyTx);
    }
    source.setNameMap(txMap);
    return new TransactionInterceptor(transactionManager, source);
  }

  /**
   * 注册事务
   * @param txAdvice
   * @return
   */
  @Bean
  public Advisor txAdviceAdvisor(TransactionInterceptor txAdvice) {
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
    return new DefaultPointcutAdvisor(pointcut, txAdvice);
  }

}